package com.dlc.shop.api.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dlc.shop.api.util.InvitationCodeUtil;
import com.google.common.collect.Lists;
import com.dlc.shop.bean.app.dto.*;
import com.dlc.shop.bean.app.param.OrderParam;
import com.dlc.shop.bean.app.param.OrderPayInfoParam;
import com.dlc.shop.bean.app.param.SubmitOrderParam;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.EsProductUpdateEvent;
import com.dlc.shop.bean.event.SubmitSeckillOrderEvent;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.ChooseCouponParam;
import com.dlc.shop.bean.param.PlatformChooseCouponParam;
import com.dlc.shop.bean.vo.UserDeliveryInfoVO;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ResponseEnum;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.BeanUtil;
import com.dlc.shop.delivery.api.manager.DeliveryOrderManager;
import com.dlc.shop.delivery.api.manager.StationOrderManager;
import com.dlc.shop.manager.*;
import com.dlc.shop.manager.impl.ConfirmOrderManager;
import com.dlc.shop.manager.impl.ShopCartAdapter;
import com.dlc.shop.manager.impl.ShopCartItemAdapter;
import com.dlc.shop.security.api.util.SecurityUtils;
import com.dlc.shop.service.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author LGH
 */
@Slf4j
@RestController
@RequestMapping("/p/order")
@Tag(name = "订单接口")
@AllArgsConstructor
public class OrderController {

    private final OrderService orderService;
    private final SubmitOrderManager submitOrderManager;
    private final SkuService skuService;
    private final ProductService productService;
    private final ApplicationContext applicationContext;
    private final UserAddrOrderService userAddrOrderService;
    private final ApplicationEventPublisher eventPublisher;
    private final ShopCartAdapter shopCartAdapter;
    private final ShopCartItemAdapter shopCartItemAdapter;
    private final ConfirmOrderManager confirmOrderManager;
    private final ThreadPoolExecutor orderThreadPoolExecutor;
    private final DeliveryOrderManager deliveryOrderManager;
    private final StationOrderManager stationOrderManager;
    private final DiscountShopCartManager discountShopCartManager;
    private final ComboShopCartManager comboShopCartManager;
    private final CouponConfirmOrderManager couponConfirmOrderManager;
    private final UserLevelOrderManager userLevelOrderManager;
    private final OrderUseScoreManager orderUseScoreManager;
    private final ShopCustomerService shopCustomerService;
    private final UserAddrService userAddrService;
    private final FlowLogService flowLogService;

    private final ZeroPreOrderService zeroPreOrderService;

    @PostMapping("/confirm")
    @Operation(summary = "结算，生成普通订单信息" , description = "传入下单所需要的参数进行下单")
    public ServerResponseEntity<ShopCartOrderMergerDto> confirm(@Valid @RequestBody OrderParam orderParam) throws ExecutionException, InterruptedException {
        //pc端 立即购买设置配送方式
        setParmamDvytype(orderParam);
        String userId = SecurityUtils.getUser().getUserId();
        // 将要返回给前端的完整的订单信息，初始化
        ShopCartOrderMergerDto shopCartOrderMerger = setMergerDto(orderParam, userId);
        // 组装获取用户提交的购物车商品项
        List<ShopCartItemDto> shopCartItemsDb = shopCartItemAdapter.getShopCartItemsByOrderItems(orderParam, userId, orderParam.getAddrId());
        //pc端 购物车下单设置配送方式
        this.setCartDvytype(orderParam, shopCartItemsDb, shopCartOrderMerger);
        // 获取用户地址信息
        UserDeliveryInfoVO userDeliveryInfoVO = confirmOrderManager.getUserDeliveryInfoVO(shopCartItemsDb, userId, orderParam.getDvyTypes(), orderParam.getAddrId());
        // 筛选过滤掉不同配送的商品
        List<ShopCartItemDto> shopCartItems = confirmOrderManager.filterShopItemsByType(shopCartOrderMerger, userDeliveryInfoVO, shopCartItemsDb);
        // 该商品不满足任何的配送方式
        if (CollectionUtil.isEmpty(shopCartItems)) {
            log.info("该商品不满足任何的配送方式，组装用户地址");
            seMergerUserAddr(orderParam, userId, shopCartOrderMerger);
            return ServerResponseEntity.success(shopCartOrderMerger);
        }
        // 自提订单处理
        stationOrderManager.handleStationOrder(shopCartOrderMerger, shopCartItems, userDeliveryInfoVO);
        // 商品类别 0.实物商品 1. 虚拟商品 2.组合商品
        int mold = 0;
        // 判断订单类型
        checkOrderType(shopCartOrderMerger, shopCartItems, orderParam, mold);
        // 购物车
        List<ShopCartDto> shopCarts = shopCartAdapter.getShopCarts(shopCartItems);
        // 计算满减，并重新组合购物车
        if (discountShopCartManager != null) {
            shopCarts = discountShopCartManager.calculateDiscountAndMakeUpShopCart(shopCarts);
        }
        // 计算套餐，并重新组合购物车
        if (comboShopCartManager != null) {
            shopCarts = comboShopCartManager.calculateDiscountAndMakeUpShopCart(shopCarts);
        }
        // 异步计算运费，运费暂时和优惠券没啥关联，可以与优惠券异步计算，获取用户地址，自提信息
        CompletableFuture<UserDeliveryInfoVO> deliveryFuture = null;
        if (!Objects.equals(mold, 1)) {
            deliveryFuture = CompletableFuture.supplyAsync(
                    () -> deliveryOrderManager.calculateAndGetDeliverInfo(shopCartItems, userDeliveryInfoVO),
                    orderThreadPoolExecutor);
        }

        // 运费用异步计算，最后要等运费出结果
        UserDeliveryInfoVO userDeliveryInfo = new UserDeliveryInfoVO();
        if (Objects.nonNull(deliveryFuture)) {
            userDeliveryInfo = deliveryFuture.get();
        }
        // 计算优惠券，并返回优惠券信息
        if (couponConfirmOrderManager != null) {
            shopCarts = couponConfirmOrderManager.chooseShopCoupon(new ChooseCouponParam(orderParam.getUserChangeCoupon(), orderParam.getCouponUserIds(), shopCarts));
        }
        // 当算完一遍店铺的各种满减活动时，重算一遍订单金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculateShop(shopCartOrderMerger, shopCarts, userDeliveryInfo);

        // 等活动处理完之后，再插入sku的库存区域id -- 赠品、套餐和组合商品需要在marketing模块中处理
        confirmOrderManager.handleShopCartStockPoint(userDeliveryInfoVO, shopCarts, shopCartItemsDb, shopCartOrderMerger.getMold());

        double orderShopReduce = shopCartOrderMerger.getOrderReduce();
        // 店铺会员等级优惠计算
        if (userLevelOrderManager != null) {
            userLevelOrderManager.calShopLevelDiscount(shopCartOrderMerger);
        }
        confirmOrderManager.reCalAmountWhenFinishCalShop(shopCartOrderMerger);
        // ===============================================开始平台优惠的计算==================================================
        // 计算平台优惠券，并返回平台优惠券信息
        if (couponConfirmOrderManager != null) {
            shopCartOrderMerger = couponConfirmOrderManager.choosePlatformCoupon(new PlatformChooseCouponParam(orderParam.getUserChangeCoupon(), orderParam.getCouponUserIds(), shopCartOrderMerger));
        }
        // 等级折扣
        if (userLevelOrderManager != null) {
            userLevelOrderManager.calculateLevelDiscount(shopCartOrderMerger);
        }
        // ===============================================结束平台优惠的计算==================================================
        // 结束平台优惠的计算之后，还要重算一遍金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculatePlatform(shopCartOrderMerger);
        // 计算订单积分抵扣金额
        if (orderUseScoreManager != null) {
            orderUseScoreManager.orderUseScore(shopCartOrderMerger, orderParam, shopCartItems);
        }
        shopCartOrderMerger.setOrderShopReduce(orderShopReduce);
        // 计算平台佣金
        confirmOrderManager.calculatePlatformCommission(shopCartOrderMerger);
        // 缓存计算
        confirmOrderManager.cacheCalculatedInfo(userId, shopCartOrderMerger);
        return ServerResponseEntity.success(shopCartOrderMerger);
    }

    @PostMapping("/submit")
    @Operation(summary = "提交订单，返回支付流水号" , description = "根据传入的参数判断是否为购物车提交订单，同时对购物车进行删除，用户开始进行支付，根据店铺进行拆单")
    public ServerResponseEntity<OrderNumbersDto> submitOrders(@Valid @RequestBody SubmitOrderParam submitOrderParam) {
        String userId = SecurityUtils.getUser().getUserId();
        ServerResponseEntity<ShopCartOrderMergerDto> orderCheckResult = submitOrderManager.checkSubmitInfo(submitOrderParam, userId);
        if (!orderCheckResult.isSuccess()) {
            if(StrUtil.equals(ResponseEnum.REPEAT_ORDER.value(),orderCheckResult.getCode())){
                OrderNumbersDto orderNumbersDto = new OrderNumbersDto(null);
                orderNumbersDto.setDuplicateError(1);
                return ServerResponseEntity.success(orderNumbersDto);
            }
        }
        ShopCartOrderMergerDto mergerOrder = orderCheckResult.getData();

        List<ShopCartOrderDto> shopCartOrders = mergerOrder.getShopCartOrders();
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {
            List<ShopCartItemDiscountDto> shopCartItemDiscounts = shopCartOrder.getShopCartItemDiscounts();
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemDto> shopCartItems = shopCartItemDiscount.getShopCartItems();
                for (ShopCartItemDto shopCartItem : shopCartItems) {
                    Long prodId = shopCartItem.getProdId();
                    Product productById = productService.getProductById(prodId);
                    if(!productById.getStatus().equals(ProdStatusEnums.NORMAL.getValue())){
                        throw new YamiShopBindException("商品:["+productById.getProdName()+"]已下架");
                    }
                }
            }
        }
        List<Order> orders = orderService.submit(mergerOrder);
        StringBuilder orderNumbers = new StringBuilder();
        for (Order order : orders) {
            orderNumbers.append(order.getOrderNumber()).append(StrUtil.COMMA);
        }
        orderNumbers.deleteCharAt(orderNumbers.length() - 1);
        // 店铺客户创建
        shopCustomerService.saveCustomerByOrders(orders);

        // 移除缓存
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartOrder.getShopCartItemDiscounts()) {
                for (ShopCartItemDto shopCartItem : shopCartItemDiscount.getShopCartItems()) {
                    skuService.removeSkuCacheBySkuId(shopCartItem.getSkuId(), shopCartItem.getProdId());
                    productService.removeProdCacheByProdId(shopCartItem.getProdId());
                }
            }
        }
        orderService.removeConfirmOrderCache(userId + submitOrderParam.getUuid());
        // 更新es中的商品库存--更新失败打印日志，优先保证订单流程没问题
        try {
            eventPublisher.publishEvent(new EsProductUpdateEvent(mergerOrder.getProdList(), EsOperationType.UPDATE_ORDER_STOCK_NUM_BATCH));
        } catch (Exception e) {
            log.error("提交订单-更新es商品库存失败，错误为:", e);
        }
        // 插入流量数据
        flowLogService.saveSubmitOrder(submitOrderParam.getOrderFlowLogParam(), userId, orderNumbers.toString());
        return ServerResponseEntity.success(new OrderNumbersDto(orderNumbers.toString()));
    }

    @GetMapping("/getOrderPayInfoByOrderNumber")
    @Operation(summary = "获取订单支付信息" , description = "获取订单支付的商品/地址信息")
    @Parameter(name = "orderNumbers", description = "订单流水号" , required = true)
    public ServerResponseEntity<OrderPayInfoParam> getOrderPayInfoByOrderNumber(@RequestParam("orderNumbers") String orderNumbers) {
        String userId = SecurityUtils.getUser().getUserId();
        List<String> orderNumberList = Arrays.asList(orderNumbers.split(StrUtil.COMMA));
        //获取订单信息
        List<Order> orderList = orderService.getOrderPayInfoByOrderNumber(orderNumberList);
        List<String> prodNameList = Lists.newArrayList();
        Long addrOrderId = null;
        Date endTime = null;
        int totalScore = 0;
        double totalFee = 0.0;
        boolean isStation = false;
        boolean hasAddr = false;
        Integer status = 1;
        Order orderDb = new Order();
        //获取商品名集合
        for (Order order : orderList) {
            if (!Objects.equals(userId, order.getUserId())) {
                throw new YamiShopBindException("yami.order.no.exist");
            }
            for (OrderItem orderItem : order.getOrderItems()) {
                prodNameList.add(orderItem.getProdName());
                totalScore += orderItem.getUseScore() != null ? orderItem.getUseScore() : 0;
            }
            //第一次循环，获取订单地址id，订单过期时间
            if (Objects.isNull(addrOrderId)) {
                addrOrderId = order.getAddrOrderId();
                if (Objects.equals(2, order.getOrderType())) {
                    // 获取秒杀订单的取消订单时间
                    Integer maxCancelTime = 0;
                    SubmitSeckillOrderEvent event = new SubmitSeckillOrderEvent(order, maxCancelTime);
                    applicationContext.publishEvent(event);
                    maxCancelTime = event.getMaxCancelTime();
                    if (maxCancelTime <= 0) {
                        maxCancelTime = 30;
                    }
                    endTime = DateUtil.offsetMinute(order.getCreateTime(), maxCancelTime);
                } else {
                    endTime = DateUtil.offsetMinute(order.getCreateTime(), 30);
                }
            }
            totalFee = Arith.add(totalFee, order.getActualTotal());
            if (Objects.equals(order.getDvyType(), DvyType.STATION.value())) {
                isStation = true;
                orderDb = order;
            }
            if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value())) {
                status = order.getStatus();
            }
            if (!hasAddr && !Objects.equals(order.getOrderMold(), 1)) {
                addrOrderId = order.getAddrOrderId();
                hasAddr = true;
            }
        }
        OrderPayInfoParam orderPayInfoParam = new OrderPayInfoParam();
        orderPayInfoParam.setStatus(status);
        orderPayInfoParam.setProdNameList(prodNameList);
        orderPayInfoParam.setEndTime(endTime);
        orderPayInfoParam.setTotalFee(totalFee);
        orderPayInfoParam.setTotalScore(totalScore);
        if (isStation) {
            orderPayInfoParam.setUserAddr("");
            orderPayInfoParam.setReceiver(orderDb.getReceiverName());
            orderPayInfoParam.setMobile(orderDb.getReceiverMobile());
        } else if (hasAddr) {
            //写入商品名、收货地址/电话
            UserAddrOrder userAddrOrder = userAddrOrderService.getById(addrOrderId);
            String addr = userAddrOrder.getProvince() + userAddrOrder.getCity() + userAddrOrder.getArea() + userAddrOrder.getAddr();
            orderPayInfoParam.setUserAddr(addr);
            orderPayInfoParam.setReceiver(userAddrOrder.getReceiver());
            orderPayInfoParam.setMobile(userAddrOrder.getMobile());
        }
        return ServerResponseEntity.success(orderPayInfoParam);
    }

    private ShopCartOrderMergerDto setMergerDto(OrderParam orderParam, String userId) {
        ShopCartOrderMergerDto shopCartOrderMerger = new ShopCartOrderMergerDto();
        shopCartOrderMerger.setUserId(userId);
        shopCartOrderMerger.setIsScorePay(orderParam.getIsScorePay());
        shopCartOrderMerger.setDvyTypes(orderParam.getDvyTypes());
        shopCartOrderMerger.setUsableScore(orderParam.getUserUseScore());
        shopCartOrderMerger.setOrderType(OrderType.ORDINARY);
        return shopCartOrderMerger;
    }

    private void setParmamDvytype(OrderParam orderParam) {
        if (Objects.isNull(orderParam.getDvyTypes()) && Objects.nonNull(orderParam.getOrderItem())){
            log.info("pc端直接下单，默认配送方式为快递");
            orderParam.setDvyTypes(Collections.singletonList(new DvyTypeDTO(orderParam.getOrderItem().getShopId(), DvyType.DELIVERY.value())));
        }
    }

    private void setCartDvytype(OrderParam orderParam, List<ShopCartItemDto> shopCartItemsDb, ShopCartOrderMergerDto shopCartOrderMerger) {
        if (Objects.isNull(orderParam.getDvyTypes()) && CollectionUtil.isNotEmpty(shopCartItemsDb)) {
            //购物车下单
            log.info("PC端购物车下单，默认配送方式为快递");
            List<DvyTypeDTO> dvyTypes = new ArrayList<>();
            Set<Long> shopIdSet = shopCartItemsDb.stream().map(ShopCartItemDto::getShopId).collect(Collectors.toSet());
            shopIdSet.forEach(shopId -> dvyTypes.add(new DvyTypeDTO(shopId, DvyType.DELIVERY.value())));
            orderParam.setDvyTypes(dvyTypes);
            shopCartOrderMerger.setDvyTypes(dvyTypes);
        }
    }

    private void seMergerUserAddr(OrderParam orderParam, String userId, ShopCartOrderMergerDto shopCartOrderMerger){
        //订单的地址信息
        UserAddr userAddr = userAddrService.getUserAddrByUserId(orderParam.getAddrId(), userId);
        shopCartOrderMerger.setUserAddr(BeanUtil.map(userAddr, UserAddrDto.class));
        shopCartOrderMerger.setShopCartOrders(new ArrayList<>());
    }

    private void checkOrderType(ShopCartOrderMergerDto shopCartOrderMerger, List<ShopCartItemDto> shopCartItems, OrderParam orderParam, int mold) {
        ShopCartItemDto firstShopCartItem = shopCartItems.get(0);
        // 是否为预售订单
        orderParam.setPreSellStatus(firstShopCartItem.getPreSellStatus());
        shopCartOrderMerger.setPreSellStatus(firstShopCartItem.getPreSellStatus());
        if (shopCartItems.stream().filter(shopCartItemDto -> shopCartItemDto.getMold() == 1).count() == shopCartItems.size()) {
            // 订单项中的所有商品都为虚拟商品时，才是虚拟订单
            log.info("判断该订单所有商品是否都是虚拟商品");
            mold = 1;
            shopCartOrderMerger.getDvyTypes().forEach(s->s.setDvyType(DeliveryType.NO_EXPRESS.getValue()));
        }
        shopCartOrderMerger.setMold(mold);
    }

    @PostMapping("/createZeroOrder")
    @Operation(summary = "生成零元购订单信息" , description = "传入零元购下单所需要的参数进行下单")
    public ServerResponseEntity<ZeroPreOrder> createZeroOrder(@RequestBody ZeroPreOrder zeroPreOrder){
        long count = zeroPreOrderService.count(new LambdaQueryWrapper<ZeroPreOrder>()
                .eq(ZeroPreOrder::getUserId, zeroPreOrder.getUserId())
                .eq(ZeroPreOrder::getStatus, 0));
        if(count > 0){
            return ServerResponseEntity.showFailMsg("您有正在参加的零元购，请先完成");
        }else {

            //生成邀请码
            String inviteCode = InvitationCodeUtil.generateInviteCode1();
            do{
                inviteCode = InvitationCodeUtil.generateInviteCode1();
            }while (getConunt(inviteCode) > 0);

            zeroPreOrder.setInvitationCode(inviteCode);

            zeroPreOrderService.save(zeroPreOrder);
        }
        return ServerResponseEntity.success();
    }

    public long getConunt(String inviteCode){
        long codeCount = zeroPreOrderService.count(new LambdaQueryWrapper<ZeroPreOrder>()
                .eq(ZeroPreOrder::getInvitationCode, inviteCode));
        return codeCount;
    }

}
